package com.ncmem.up6.utils;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import com.ncmem.up6.model.FileInf;

/**
 * 
 * @author zysoft
 * 用法：
 *
 */
public class CryptoTool
{
	private String key = "2C4DD1CC9KAX4TA9";
	private String iv = "2C4DD1CC9KAX4TA9";
	 //算法名称
	private String KEY_ALGORITHM = "AES";
	 //加密算法，填充方式
	 private String algorithm = "AES/CBC/NoPadding";

	
	public CryptoTool()
	{		
	}

	/**
	 *
	 * @param data
	 * @param base64 是否使用base64编码
	 * @return
	 */
	public String aes_cbc_pkcs(String data,boolean base64)
	{
		try
		{
			Cipher cipher = Cipher.getInstance(this.algorithm,"BC");
			byte[] src = data.getBytes("UTF-8");// byte[plaintextLength];

			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

			cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
			byte[] encrypted = cipher.doFinal(src);

			if(base64)
				return new sun.misc.BASE64Encoder().encode(encrypted);

			return Hex.encodeHexString(encrypted);

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public String encrypt(String data) throws Exception 
	{
	    try 
	    {
	    	byte[] buf = data.getBytes("UTF-8");
	    	if((buf.length%16) >0)
			{
				int len = 16 - buf.length%16;
				buf = Arrays.copyOf(buf,buf.length+len);
			}

	    	Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
	        Cipher cipher = Cipher.getInstance(this.algorithm);

	        SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
	        IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
	
	        cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
	        byte[] cry = cipher.doFinal(buf);
	        String str = new sun.misc.BASE64Encoder().encode(cry);
	        return str.trim();
	
	    } catch (Exception e) {
	        e.printStackTrace();
	        return null;
	    }
	}

    public String decrypt(String data)
    {
        try
        {
            byte[] cry = new BASE64Decoder().decodeBuffer(data);
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance(this.algorithm);
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
            byte[] decry = cipher.doFinal(cry);

            String str = new String(decry,"UTF-8");
            return str.trim();
        }
        catch (Exception e) 
        {
            e.printStackTrace();
            return null;
        }
    }

	public ByteArrayOutputStream decrypt(String aligo, ByteArrayOutputStream block)
	{
		if(aligo.equalsIgnoreCase("sm4")) return this.sm4_decode(block);
		else if (aligo.equalsIgnoreCase("aes/ecb")) return this.aes_ecb_decode(block);
		return this.aes_decode(block);
	}

	/**
	 * aes/cbc/pkcs
	 * @param s  加密后的数据(16byte对齐)
	 * @return
	 */
	private ByteArrayOutputStream aes_decode(ByteArrayOutputStream s) {

		try
		{
			byte[] buf = s.toByteArray();
			String ago="AES/CBC/PKCS5Padding";
			this.KEY_ALGORITHM="AES";

			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(ago, BouncyCastleProvider.PROVIDER_NAME);
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

			cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

			byte[] out = cipher.doFinal(buf);
			ByteArrayOutputStream ost = new ByteArrayOutputStream();
			ost.write(out,0,out.length);
			return ost;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	private ByteArrayOutputStream aes_ecb_decode(ByteArrayOutputStream s) {

		return s;
	}

	/**
	 * SM4/ECB/PKCS5Padding
	 * @param stm
	 * @param lenOri
	 * @return
	 */
	public ByteArrayOutputStream sm4_encode(ByteArrayOutputStream stm, int lenOri)
	{
		try
		{
			byte[] buf = stm.toByteArray();

			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(this.algorithm,"BC");
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

			cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

			byte[] out = cipher.doFinal(buf);
			ByteArrayOutputStream ost = new ByteArrayOutputStream();
			ost.write(out,0,lenOri);
			return ost;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * SM4/ECB/PKCS5Padding
	 * @param s
	 * @return
	 */
	private ByteArrayOutputStream sm4_decode(ByteArrayOutputStream s)
	{
		try
		{
			byte[] buf = s.toByteArray();
			String ago="SM4/CBC/PKCS5Padding";
			this.KEY_ALGORITHM="SM4";

			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(ago, BouncyCastleProvider.PROVIDER_NAME);
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

			cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

			byte[] out = cipher.doFinal(buf);
			ByteArrayOutputStream ost = new ByteArrayOutputStream();
			ost.write(out,0,out.length);
			return ost;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	public String token(FileInf f,String action)
	{
		String str = f.id + f.nameLoc + action;
		if(action == "block") str = f.id + f.pathSvr + action;
		str = Md5Tool.getMD5(str);
		try {
			str = this.encrypt(str);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return str;
	}
}